Simple Programs Using PIC16F877 Microcontroller

PIC16F877 is one of the advanced and commonly used Peripheral Interface Microcontrollefrom Microchip. Simplicity, quality, ease of availability and low price makes them ideal for different applications. Also, this PIC features all components that modern microcontrollers have.

Some of the remarkable features of this PIC microcontroller are listed below.

General Features

  • 35 instructions are only there.
  • Single-cycle instructions are used here. While, two-cycle instructions are used for program branches.
  • DC – 20 MHz clock input DC – 200 ns instruction cycle is the operating speed.8K x 14 words of Flash Program Memory, Data Memory RAM of 368 x 8 bytes, EEPROM Data Memory of 256 x 8 bytes.Pin out compatible to other 28-pin or 40/44-pin.Voltage range of 2 to 5.5 V.
  • Low-power, high-speed Flash/EEPROM technology.
  • Low-power consumption.
  • Static design.

Some of the Peripheral Features

Analog Features

  • Analog Comparator module present.
  • 10-bit, upto 8-channel Analog-to-Digital Converter (A/D).

Other Features

  • Selectable oscillator options.
  • Data EEPROM Retention > 40 years.
  • In-Circuit Debug (ICD) via two pins.
  • 100,000 erase/write cycle Enhanced Flash program memory.
  • 1,000,000 erase/write cycle Data EEPROM memory.
  • Self-reprogrammable.
  • In-Circuit Serial Programming via two pins.
  • Programmable code protection.
  • Power saving Sleep mode.
  • Watchdog Timer with RC oscillator.

Pin Diagram

pic16f877

Input/output ports

PIC16F877 has 5 basic I/O ports. These are denoted by PORT A, PORT B, PORT C, PORT D, and PORT E. These ports are used for input/ output interfacing.

Input/ Output Ports

Features of Input/Output Ports.

  • All these ports are bi-directional.
  • Directions of ports are controlled by using TRIS(X) registers.
  • TRIS A helps in setting PORT-A direction. Likewise, TRISB, TRIS C and TRIS D set the direction of other ports.
  • Setting a TRIS(X) bit ‘1’ will set the corresponding PORT(X) bit as input.
  • Clearing a TRIS(X) bit ‘0’ will set the corresponding PORT(X) bit as output.

Note: If we want to set PORT A as an input, just set TRIS(A) bit to logical ‘1’ and want to set PORT B as an output, just set the PORT B bits to logical ‘0’.

Sample Program

Program1: 

// the port testing program which toggles all the port pins

#include <pic.h>

#include"delay.h"// THE DELAY FUNCTION IS ATTACHED

//This subfunction configures the ports of pic as output

void TRISCONFIG ()

                {

                                TRISA = 0; //configuring portA 

                                TRISB = 0; //configuring portB

                                TRISC = 0; //configuring portC

                                TRISD = 0; //configuring portD

                                TRISE = 0; //configuring portE

                                // INTIALISING ALL THE PORTS WITH ZEROS

                                PORTA=0;

                                PORTB=0;

                                PORTC=0;

                                PORTD=0;

                                PORTE=0;

                                }

void main ()

{

TRISCONFIG (); // CALLING OF PORT CONFIG FUNCTION  

while (1)//looping continuously

{

PORTA=~PORTA; // toggling the port values so as to make it blink

PORTB=~PORTB;

PORTC=~PORTC;

PORTD=~PORTD;

PORTE=~PORTE;

DelayMs (500);// CALLING A DELAY OF 500 MS TWICE : REFER DELAY.C

DelayMs (500);

}              

}

Program2: 2ND PORT

// THE PORT program for interfacing switches and led

// connect the switches in pull up state to portb

// connect the leds to portd

// whenever a switch in the portb is kept pressed the ledsin portd toggles


#include <pic.h>

#include"delay.h"// THE DELAY FUNCTION IS ATTACHED

//This subfunction configures the ports of pic as output and input

          void TRISCONFIG()

                   {

                   TRISB = 0xFF; //configuring portB as input

                   TRISD = 0; //configuring portD as output

                   // INTIALISING ALL THE PORTD WITH ZEROS

                   PORTD=0;

                   PORTE=~PORTE;

                   DelayMs(500);// CALLING A DELAY OF 500 MS TWICE : REFER DELAY.C

                   DelayMs(500);

                   }                 

                   void main()

                   {

                   TRISCONFIG(); // CALLING OF PORT CONFIG FUNCTION

                   while(1)//looping continously

                   {

                   if(PORTB!=0XFF) //check for key press in portb

                   {

                   PORTE=~PORTE;

                   DelayMs(500);// CALLING A DELAY OF 500 MS TWICE : REFER DELAY.C

                   DelayMs(500);  

                   }

                   }

}

UART

The Universal Synchronous Asynchronous Receiver Transmitter (USART) present in PIC16F877 is one among the two serial I/O modules. It can be used as a full-duplex asynchronous system which can communicate with the peripheral devices. The peripheral devices can be a CRT terminal, personal computer. Also the UART of PIC16F877 can be used as a half-duplex synchronous system. This half duplex system can communicate with peripheral devices like A/D or D/A integrated circuits, serial EEPROMs etc.

The USART can be configured in the following modes:

  • Synchronous – Master (half-duplex)
  • Asynchronous (full-duplex)
  • Synchronous – Slave (half-duplex)

Bit SPEN (RCSTA<7>) and TRISC<7:6> is to be set to configure RC6/TX/CK and RC7/RX/DT as USART. USART in PIC16F877A has multi-processor communication capability using 9-bit address detection.

UART TRANSMIT REGISTER SPECIFICATION

UART Reception

UART Transmission

When setting up an UART Transmission, follow these steps:

1. Initialize SPBRG for baud rate. Inorder to set a high-speed baud rate, set BRGH.

2. Enable asynchronous serial port by clearing SYNC and set SPEN.

3. If interrupts are desired, then set TXIE.

4. For 9-bit transmission set TX9.

5. Enable transmission by setting TXEN and TXIF.

6. If 9-bit transmission is used; ninth bit must be loaded in TX9D.

7. Load data to the TXREG register.

8. If interrupts are used, make GIE and PEIE of INTCON register to set mode.

Sample Program

//transmits a string

#include <pic.h>

#include "delay.h"     // including the delay header

#define BAUD 9600      // defining the required baud rate

#define FOSC 4000000L  // define the xtal frequency provided

#define DIVIDER ((int)(FOSC/(16UL * BAUD) -1)) // equation for calculating the divider value to store in baud rate register

//refer the uart tutorial

// function to transmit a single byte through uart

 void putchs(unsigned char byte)

          {

          TXREG = byte;  /* output one byte */

          while(!TRMT) /* set when register is empty */

          continue;

          }

// this function transmits a string through uart

          void prints(const char *uptr)

                   {

                   while(*uptr != '\0')

                             {

                             putchs(*uptr);

                             uptr++;

                             DelayMs(1);

                   }

                   }

// uart intialising refer the uart tutorial for register details

                   void uart_Init()        

                   {

                   RCSTA   = 0;

                   TXSTA   = 0;

                   RCREG   = 0;

                   BRGH    = 1;   //set high baud rate

                   SYNC    = 0;  //select async communication

                   SPBRG   = DIVIDER;//  calculated from above equation, if BRGH=1;

                   SPEN    = 1;                 // serial port enable

                   TXEN    = 1;                 // transmission enable

                   GIE     = 0;  // disabling the interrupts

                   RCIF    = 0;

                   PEIE    = 0;

                   RCIE    = 1;   //enabling the reception notification flag

                   CREN    = 1;   // enabling continous reception

                   }

                   void main()

                   {

                             uart_Init(); // intialising uart

                             prints("hello world");// trasmitting string

                             while(1);// stopping from overrun

                   }

UART Reception

When setting up an UART Reception, follow these steps:

1. Initialize SPBRG for baud rate. Inorder to set a high-speed baud rate set BRGH.

2. Enable the asynchronous serial port by clearing SYNC and set SPEN.

3. If interrupts are desired, then set RCIE.

4. If 9-bit reception is used, set RX9.

5. Enable reception by setting CREN.

6. Flag bit RCIF will be set when reception is complete and an interrupt will be generated if enable bit RCIE is set.

7. Read the RCSTA register.

8. Read RCREG register.

9. Clear error by CREN.

10. If using interrupts, ensure that GIE and PEIE (bits 7 and 6) of the INTCON register are set.

Sample Program

//transmits a  a recieved byte

#include <pic.h>

#include "delay.h"      // including the delay header

#define BAUD 9600      // defining the required baud rate

#define FOSC 4000000L  // define the xtal frequency provided

#define DIVIDER ((int)(FOSC/(16UL * BAUD) -1)) // equation for calculating the divider value to store in baud rate register

 void putchs(unsigned char byte)

          {

            TXREG = byte;  /* output one byte */

                   while(!TRMT)     /* set when register is empty */

                   continue;

          }

// this function transmits a string through uart

          void prints(const char *uptr)

                   {

                   while(*uptr != '\0')

                             {

                             putchs(*uptr);

                             uptr++;

                             DelayMs(1);

                   }

                   }

// uart intialising refer the uart tutorial for register details

                   void uart_Init()  

                   {

                   RCSTA   = 0;

                   TXSTA   = 0;

                   RCREG   = 0;

                   BRGH    = 1;                   //set high baud rate

                   SYNC    = 0;                   //select async communication

                   SPBRG   = DIVIDER;//  calculated from above equation, if BRGH=1;

                   SPEN    = 1;                   // serial port enable

                   TXEN    = 1;                   // transmission enable

                   GIE     = 0;                   // disabling the interrupts

                   RCIF    = 0;

                   PEIE    = 0;

                   RCIE    = 1;                  //enabling the reception notification flag

                   CREN    = 1;                  // enabling continous reception

                   }

                   void main()

                   {

                             uart_Init(); // intialising uart


                             while(1)// looping for ever

                             {

                             while(RCIF==0);// waiting for reception

                             {

                             RCIF=0; // CLEARING THE BIT

                             putchs(RCREG);// trasmitting byte

                             }

                             }


                   }

Analog to Digital Converter

Analog-to-Digital Converter for 28-pin devices has five inputs and for 40/44-pin devices has eight inputs. In PIC16F877, conversion of analog signal results in 10-bit digital number. A/D module has low and high voltage reference input. It is software selectable for VSS, VDD, RA2, RA3. The A/D converter device can operate in Sleep mode. During Sleep, clock of the converter must be derived from the RC oscillator.

The A/D in PIC16F877A has four registers. These registers are:

• A/D Control Register 0 (ADCON0)

• A/D Result High Register (ADRESH)

• A/D Result Low Register (ADRESL)

• A/D Control Register 1 (ADCON1)

ADCON1

ADCON0

To do an A/D Conversion, follow these steps:

1. Configure A/D module

• Configure analog pins and digital I/O (ADCON1)

• Select A/D input channel (ADCON0)

• Select A/D conversion clock (ADCON0)

• Turn ON A/D module (ADCON0)

2. Configure A/D interrupt (if desired)

• Clear ADIF

• Set ADIE

• Set PEIE

• Set GIE

3. Wait for acquisition time.

4. Start conversion

• Set GO/DONE bit (ADCON0)

5. Wait for A/D conversion to complete by either:

• Polling GO/DONE bit to be cleared or,

• Wait for A/D interrupt.

6. Read A/D Result register, clear ADIF.

7. For next conversion, go to step 1 or step 2 as required. A/D conversion time per bit is defined as TAD.

Sample Program

#include <pic.h>

#include"delay.h"

int adcval; // defining adc integer

 void ADC_Init()

                   {

                   TRISA  = 0XEF;//configuring adc  ports as input

                   TRISE  = 0X07;

                   ADCON1 = 0X80;// configuring all ports as analog ports

                   }

// fucntion for reading the adc value

int read_adc(char channel)

    {

    int val;

    ADCON1 = 0x80; //port config

    ADCON0 = 0x81 | channel << 3;// channel selection SET THE CHANNEL NUMBER

    DelayUs(50);

    ADGO   = 1;//turn on the adc

    while(ADGO)   // checking the adc conversion

        continue;

    val = ADRESH;

    val = val<<8 | ADRESL;// combining the both adresh and adresl values to a single variable

    return (val);

    }

          void main()

          {

          TRISD=0X00;     

          PORTD=0X00;

          ADC_Init();// adcintialising

          while(1)// loop for ever

          {

          adcval=read_adc(0);

          if(adcval> 500)  //checking the adc value

          {

          PORTD=0XFF; //setting the port value as high  if adc value greater than 500

          }

          else  // reseting the port value

          {

          PORTD=0X00;

          }

          }

          }

PWM

A PWM output has a time base and a time that the output stays high. Frequency of PWM is inverse of period.

PWM PERIOD

PWM period is specified by PR2 register. PWM period can be calculated using the formula:

PWM Period = [(PR2) + 1] • 4 • TOSC • (TMR2 Prescaler Value)

PWM frequency is defined by 1/ [PWM period].

When TMR2 is equal to PR2, first:

• TMR2 is cleared.

• CCP1 pin is set.

• PWM duty cycle is passed from CCPR1L to CCPR1H.

PWM DUTY CYCLE

PWM Duty Cycle = (CCPR1L:CCP1CON<5:4>) • TOSC • (TMR2 Prescaler Value)

The following steps should be taken when configuring the CCP module for PWM operation:

1. Set PWM period by PR2 register.

2. Set PWM duty cycle by writing to CCPR1L register and CCP1CON

3. Make the CCP1 pin an output.

4. Set TMR2 prescaler value and enable Timer2 by writing to T2CON.

5. Configure CCP1 module for PWM operation.

CCP1

Sample Program

//generating the pwm from pwm1 module


#include <pic.h>

 void pwm_Init(){

                   PR2  = 41;//setting the pwm frequency

                   CCP1CON  = 0X0C;//configuring the pwm

                   CCPR1L  = 0x13; // setting the duty cycle

                   T2CKPS1 = 0;   //setting the prescalar

                   T2CKPS0 = 0;

                   TMR2IF  = 0;

                   TMR2IE  = 0;

                   TMR2ON  = 1;              //timer 2 on

                   }

                   void main()

                   {

                   pwm_Init();// intialising the pwm

                   while(1);   //stopping the program

                   }

//configuring the different timers

//subroutines for configuring the different timers

#include <pic.h>

// timer 0 intialising function

void Timer0_Init()

                   {

                   T0CS =1;// timer clock source select

                   T0IF =0;     // timer set flag

                   PSA  =0;     //prescalar assingment

                   PS2  =1;     // prescale bits

                   PS1  =1;

                   PS0  =1;

                   TMR0 =160;

                   GIE  =1;                //interrupts flag set

                   T0IE =1;               // timer interrupt set

                   PEIE =1;

                   }

// timer 2 intialising function

void Timer2_Init()

             {

                   PR2  = 95;                   // period register

                   TOUTPS0 = 1;

                   TOUTPS1 = 1;               // post scale bit

                   TOUTPS2 = 1;

                   TOUTPS3 = 1;                        

                   TMR2ON  = 0;                // timer on bit

                   TMR2    = 0;

                   T2CKPS1 = 1;                // timer prescale bit

                   T2CKPS0 = 1;

                   TMR2IF  = 0;                 //interrupt enable bits

                   TMR2IE  = 1;

                   PEIE = 1;

                   }

// timer 1 intialising function

void Timer1_Init()

                   {

                   T1CON = 0;

                   TMR1H   = 0x00;            // timer register

                   TMR1L   = 0x00;

                   TMR1ON  = 0;              // timer on bit

                   TMR1CS  = 0;

                   T1OSCEN = 0;              // timer oscillator bit select

                   T1CKPS1 = 0;

                   T1CKPS0 = 0;              // prescale bit select

                   TMR1IE  = 0;

                   TMR1IF  = 0;               // interrupt bit select

                   }


// counter 1 intialising function

void counter_Init()

                   {

                   T1CON = 0;

                   TMR1H   = 0x00;                  

                   TMR1L   = 0x00;

                   TMR1ON  = 0;

                   TMR1CS  = 1;

                   T1SYNC  = 1;

                   T1OSCEN = 0;

                   TRISC0 = 1;

                   }
Related Items